"""
策略基类
"""
import asyncio
import logging
from abc import ABC, abstractmethod
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Any
import pandas as pd
import numpy as np

from ..core.database import db_manager, TradeRecord
from ..core.logger import trading_logger
from ..services.risk_manager import risk_manager

logger = logging.getLogger(__name__)


class BaseStrategy(ABC):
    """策略基类"""
    
    def __init__(self, strategy_id: str, name: str, parameters: Dict):
        self.strategy_id = strategy_id
        self.name = name
        self.parameters = parameters
        self.is_active = False
        self.positions = {}  # symbol -> position info
        self.trade_history = []
        self.statistics = {
            "total_trades": 0,
            "winning_trades": 0,
            "losing_trades": 0,
            "total_pnl": 0.0,
            "max_drawdown": 0.0,
            "win_rate": 0.0,
            "profit_factor": 0.0
        }
        self.data_buffer = {}  # symbol -> price data
        self.last_signal_time = {}
        
    @abstractmethod
    def get_subscribed_symbols(self) -> List[str]:
        """获取订阅的合约列表"""
        pass
    
    @abstractmethod
    def is_subscribed(self, symbol: str) -> bool:
        """是否订阅了该合约"""
        pass
    
    @abstractmethod
    async def on_market_data(self, symbol: str, data: Dict):
        """处理行情数据"""
        pass
    
    @abstractmethod
    async def generate_signal(self, symbol: str, data: Dict) -> Dict:
        """生成交易信号"""
        pass
    
    async def execute_trade(self, symbol: str, signal: Dict):
        """执行交易"""
        try:
            trade_type = signal.get("action")  # "buy" or "sell"
            quantity = signal.get("quantity", 1)
            price = signal.get("price", 0)
            reason = signal.get("reason", "")
            
            if not trade_type or not price:
                return
            
            # 风控检查
            risk_check = await risk_manager.check_trade_risk(
                self.strategy_id, symbol, trade_type, quantity, price
            )
            
            if not risk_check["allowed"]:
                logger.warning(f"交易被风控拦截: {risk_check['reason']}")
                trading_logger.log_strategy(
                    self.strategy_id,
                    f"交易被拦截: {symbol} {trade_type} {quantity}手 @ {price:.3f} - {risk_check['reason']}",
                    "warning"
                )
                return
            
            # 执行交易（这里需要调用交易引擎）
            trade_data = {
                "strategy_id": self.strategy_id,
                "symbol": symbol,
                "trade_type": trade_type,
                "quantity": quantity,
                "price": price,
                "amount": price * quantity * 10000,  # 期权合约乘数
                "commission": price * quantity * 10000 * 0.0003,  # 手续费
                "trade_time": datetime.now(),
                "status": "pending"
            }
            
            # 保存交易记录
            await db_manager.save_trade_record(trade_data)
            
            # 更新持仓
            await self._update_position(symbol, trade_type, quantity, price)
            
            # 更新统计
            self._update_statistics(trade_data)
            
            # 记录日志
            trading_logger.log_trade(
                self.strategy_id, symbol, trade_type, quantity, price, reason
            )
            
            logger.info(f"交易执行成功: {symbol} {trade_type} {quantity}手 @ {price:.3f}")
            
        except Exception as e:
            logger.error(f"执行交易失败: {e}")
            trading_logger.log_strategy(
                self.strategy_id,
                f"交易执行失败: {str(e)}",
                "error"
            )
    
    async def _update_position(self, symbol: str, trade_type: str, quantity: int, price: float):
        """更新持仓"""
        try:
            if symbol not in self.positions:
                self.positions[symbol] = {
                    "symbol": symbol,
                    "quantity": 0,
                    "avg_price": 0.0,
                    "total_cost": 0.0,
                    "current_price": price,
                    "pnl": 0.0
                }
            
            position = self.positions[symbol]
            
            if trade_type == "buy":
                # 买入
                total_cost = position["total_cost"] + price * quantity * 10000
                total_quantity = position["quantity"] + quantity
                position["avg_price"] = total_cost / (total_quantity * 10000) if total_quantity > 0 else 0
                position["quantity"] = total_quantity
                position["total_cost"] = total_cost
                
            elif trade_type == "sell":
                # 卖出
                position["quantity"] -= quantity
                if position["quantity"] <= 0:
                    # 平仓
                    del self.positions[symbol]
                    return
            
            # 更新当前价格和盈亏
            position["current_price"] = price
            if position["quantity"] > 0:
                position["pnl"] = (price - position["avg_price"]) * position["quantity"] * 10000
            
            # 保存到数据库
            position_data = {
                "strategy_id": self.strategy_id,
                "symbol": symbol,
                "quantity": position["quantity"],
                "avg_price": position["avg_price"],
                "current_price": position["current_price"],
                "pnl": position["pnl"]
            }
            
            await db_manager.update_position(position_data)
            
        except Exception as e:
            logger.error(f"更新持仓失败: {e}")
    
    def _update_statistics(self, trade_data: Dict):
        """更新统计信息"""
        try:
            self.statistics["total_trades"] += 1
            
            # 这里应该根据实际盈亏计算胜率等指标
            # 简化处理
            if trade_data["trade_type"] == "buy":
                self.statistics["winning_trades"] += 1
            else:
                self.statistics["losing_trades"] += 1
            
            # 更新胜率
            total = self.statistics["winning_trades"] + self.statistics["losing_trades"]
            if total > 0:
                self.statistics["win_rate"] = self.statistics["winning_trades"] / total
            
        except Exception as e:
            logger.error(f"更新统计信息失败: {e}")
    
    def get_positions(self) -> List[Dict]:
        """获取当前持仓"""
        return list(self.positions.values())
    
    def get_recent_trades(self, limit: int = 10) -> List[Dict]:
        """获取最近交易记录"""
        return self.trade_history[-limit:] if self.trade_history else []
    
    def get_statistics(self) -> Dict:
        """获取策略统计信息"""
        return self.statistics.copy()
    
    async def backtest(self, start_date: str, end_date: str) -> Dict:
        """回测策略"""
        try:
            # 这里应该实现具体的回测逻辑
            # 简化返回模拟结果
            
            return {
                "strategy_id": self.strategy_id,
                "start_date": start_date,
                "end_date": end_date,
                "total_return": 0.15,  # 15% 收益率
                "annual_return": 0.18,
                "max_drawdown": 0.05,
                "sharpe_ratio": 1.2,
                "win_rate": 0.65,
                "profit_factor": 1.5,
                "total_trades": 50,
                "winning_trades": 32,
                "losing_trades": 18
            }
            
        except Exception as e:
            logger.error(f"回测失败: {e}")
            return {"error": str(e)}
    
    def _calculate_technical_indicators(self, prices: pd.Series) -> Dict:
        """计算技术指标"""
        try:
            indicators = {}
            
            # 移动平均线
            indicators["ma5"] = ta.sma(prices, length=5)
            indicators["ma20"] = ta.sma(prices, length=20)
            
            # RSI
            indicators["rsi"] = ta.rsi(prices, length=14)
            
            # MACD
            macd = ta.macd(prices, fast=12, slow=26, signal=9)
            if macd is not None:
                indicators["macd"] = macd["MACD_12_26_9"]
                indicators["macd_signal"] = macd["MACDs_12_26_9"]
                indicators["macd_hist"] = macd["MACDh_12_26_9"]
            
            # 布林带
            bbands = ta.bbands(prices, length=20, std=2)
            if bbands is not None:
                indicators["bb_upper"] = bbands["BBU_20_2.0"]
                indicators["bb_middle"] = bbands["BBM_20_2.0"]
                indicators["bb_lower"] = bbands["BBL_20_2.0"]
            
            # 波动率
            returns = prices.pct_change()
            indicators["volatility"] = returns.rolling(window=20).std() * np.sqrt(252)
            
            return indicators
            
        except Exception as e:
            logger.error(f"计算技术指标失败: {e}")
            return {}
    
    def _get_signal_strength(self, signal: Dict) -> float:
        """获取信号强度"""
        # 这里应该实现信号强度计算逻辑
        return 0.8  # 简化处理
    
    def _risk_adjust_position_size(self, symbol: str, base_size: int) -> int:
        """根据风险调整仓位大小"""
        # 这里应该实现风险调整逻辑
        return base_size  # 简化处理
